<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="Oj8Kj" id="Oj8Kj"><span data-lake-id="u4ec05bc4" id="u4ec05bc4">典型回答</span></h1>
  <p data-lake-id="u04f9defa" id="u04f9defa"><span data-lake-id="u4433f24c" id="u4433f24c">Spring Boot会根据类路径中的jar包、类，为jar包里的类自动配置，这样可以极大的减少配置的数量。简单点说就是它会根据定义在classpath下的类，自动的给你生成一些Bean，并加载到Spring的Context中。</span></p>
  <p data-lake-id="u7c6da19d" id="u7c6da19d"><br></p>
  <p data-lake-id="u2f5b90ce" id="u2f5b90ce"><span data-lake-id="uad238c64" id="uad238c64">SpringBoot通过Spring 的条件配置决定哪些bean可以被配置，将这些条件定义成具体的Configuration，然后将这些Configuration配置到spring.factories文件中（这种方式Springboot 2.7.0版本已不建议使用，最新的方式是使用 /META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports ）</span></p>
  <p data-lake-id="u9d6f1e41" id="u9d6f1e41"><span data-lake-id="u1bd72996" id="u1bd72996">​</span><br></p>
  <p data-lake-id="u4fe9ea62" id="u4fe9ea62"><span data-lake-id="ud93c48fc" id="ud93c48fc">作为key: org.springframework.boot.autoconfigure.EnableAutoConfiguration的值</span></p>
  <p data-lake-id="u5299e81c" id="u5299e81c"><span data-lake-id="uff2df881" id="uff2df881">​</span><br></p>
  <p data-lake-id="u253dd35c" id="u253dd35c"><span data-lake-id="u57235062" id="u57235062">这时候，容器在启动的时候，由于使用了EnableAutoConfiguration注解，该注解Import的EnableAutoConfigurationImportSelector会去扫描classpath下的所有spring.factories文件，然后进行bean的自动化配置：</span></p>
  <p data-lake-id="u5766208c" id="u5766208c"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1678520645143-06097842-af45-47cf-b157-48d83591525d.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_23%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u847265f5" id="u847265f5"><br></p>
  <h1 data-lake-id="x7NiX" id="x7NiX"><span data-lake-id="u8216cb91" id="u8216cb91">扩展知识</span></h1>
  <p data-lake-id="u76efd7a4" id="u76efd7a4"><br></p>
  <h2 data-lake-id="sw057" id="sw057"><span data-lake-id="uf55e158a" id="uf55e158a">条件化配置</span></h2>
  <p data-lake-id="ub5ca9124" id="ub5ca9124"><br></p>
  <p data-lake-id="u98089b6e" id="u98089b6e"><span data-lake-id="uea9dbbe3" id="uea9dbbe3">假设你希望一个或多个bean只有在某种特殊的情况下才需要被创建，比如，一个应用同时服务于中美用户，要在中美部署，有的服务在美国集群中需要提供，在中国集群中就不需要提供。在Spring 4之前，要实现这种级别的条件化配置是比较复杂的，但是，Spring 4引入了一个新的</span><code data-lake-id="ud4c3babe" id="ud4c3babe"><span data-lake-id="u0948e311" id="u0948e311">@Conditional</span></code><span data-lake-id="u8f54ed15" id="u8f54ed15">注解可以有效的解决这类问题。</span></p>
  <p data-lake-id="u4f503d42" id="u4f503d42"><br></p>
  <pre lang="java"><code>
@Bean
@Conditional(ChinaEnvironmentCondition.class)
public ServiceBean serviceBean(){
    return new ServiceBean();
}
</code></pre>
  <p data-lake-id="u2e37d2bc" id="u2e37d2bc"><br></p>
  <p data-lake-id="u3f519b63" id="u3f519b63"><span data-lake-id="u021362ef" id="u021362ef">当</span><code data-lake-id="u0da54f37" id="u0da54f37"><span data-lake-id="u94becdbf" id="u94becdbf">@Conditional(ChinaEnvironmentCondition.class)</span></code><span data-lake-id="u1d4b15c3" id="u1d4b15c3">条件的值为true的时候，该</span><code data-lake-id="uf892c94f" id="uf892c94f"><span data-lake-id="ue04131c8" id="ue04131c8">ServiceBean</span></code><span data-lake-id="u510f90a6" id="u510f90a6">才会被创建，否则该bean就会被忽略。</span></p>
  <p data-lake-id="ude136daf" id="ude136daf"><br></p>
  <p data-lake-id="uf0ea9d3c" id="uf0ea9d3c"><code data-lake-id="u042d6c19" id="u042d6c19"><span data-lake-id="uc2d2f723" id="uc2d2f723">@Conditional</span></code><span data-lake-id="uc24911de" id="uc24911de">指定了一个条件。他的条件的实现是一个Java类——</span><code data-lake-id="ud6699673" id="ud6699673"><span data-lake-id="u199d546a" id="u199d546a">ChinaEnvironmentCondition</span></code><span data-lake-id="u20435730" id="u20435730">，要实现以上功能就要定义</span><code data-lake-id="uecb2d6f3" id="uecb2d6f3"><span data-lake-id="u4c60a40a" id="u4c60a40a">ChinaEnvironmentCondition</span></code><span data-lake-id="u0a625b21" id="u0a625b21">类，并继承</span><code data-lake-id="ue382aba6" id="ue382aba6"><span data-lake-id="ue920ff9e" id="ue920ff9e">Condition</span></code><span data-lake-id="ud1060ae1" id="ud1060ae1">接口并重写其中的</span><code data-lake-id="u7e878636" id="u7e878636"><span data-lake-id="u38aad216" id="u38aad216">matches</span></code><span data-lake-id="ucab80ab7" id="ucab80ab7">方法。</span></p>
  <p data-lake-id="u91bfde26" id="u91bfde26"><br></p>
  <pre lang="java"><code>
class ChinaEnvironmentCondition implements Condition{
    public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        Environment env = context.getEnvironment();
        return env.containProperty("ENV_CN");
    }
}
</code></pre>
  <p data-lake-id="u59c247c2" id="u59c247c2"><br></p>
  <p data-lake-id="u8b0c6779" id="u8b0c6779"><span data-lake-id="u8a728805" id="u8a728805">在上面的代码中，matches方法的内容比较简单，他通过给定的</span><code data-lake-id="udbfc1e5a" id="udbfc1e5a"><span data-lake-id="u3af60066" id="u3af60066">ConditionContext</span></code><span data-lake-id="u7528c5b7" id="u7528c5b7">对象进而获取</span><code data-lake-id="u6fc25be0" id="u6fc25be0"><span data-lake-id="ue7176c1c" id="ue7176c1c">Environment</span></code><span data-lake-id="u2428ea02" id="u2428ea02">对象，然后使用该对象检查环境中是否存在</span><code data-lake-id="u01d6d3ad" id="u01d6d3ad"><span data-lake-id="ueaf5bcd3" id="ueaf5bcd3">ENV_CN</span></code><span data-lake-id="ubc074fc9" id="ubc074fc9">属性。如果存在该方法则直接返回true，反之返回false。当该方法返回true的时候，就符合了</span><code data-lake-id="u1e831c38" id="u1e831c38"><span data-lake-id="ue516bfdf" id="ue516bfdf">@Conditional</span></code><span data-lake-id="uf80377e5" id="uf80377e5">指定的条件，那么</span><code data-lake-id="udb2bcd71" id="udb2bcd71"><span data-lake-id="u2818e71f" id="u2818e71f">ServiceBean</span></code><span data-lake-id="ud0ceec87" id="ud0ceec87">就会被创建。反之，如果环境中没有这个属性，那么这个</span><code data-lake-id="ua7c40e1d" id="ua7c40e1d"><span data-lake-id="uc9023d6a" id="uc9023d6a">ServiceBean</span></code><span data-lake-id="ufc4b8042" id="ufc4b8042">就不会被创建。</span></p>
  <p data-lake-id="u262336ac" id="u262336ac"><br></p>
  <p data-lake-id="u0ab7d76a" id="u0ab7d76a"><span data-lake-id="u34cc2bc0" id="u34cc2bc0">除了可以自定义一些条件之外，Spring 4本身提供了很多已有的条件供直接使用，如：</span></p>
  <p data-lake-id="ue997bca1" id="ue997bca1"><br></p>
  <pre lang="java"><code>
@ConditionalOnBean
@ConditionalOnClass
@ConditionalOnExpression
@ConditionalOnMissingBean
@ConditionalOnMissingClass
@ConditionalOnNotWebApplication
</code></pre>
  <h2 data-lake-id="EDQAq" id="EDQAq"><span data-lake-id="u6ff95af0" id="u6ff95af0">Spring Boot应用的启动入口</span></h2>
  <p data-lake-id="u7ebc865c" id="u7ebc865c"><br></p>
  <p data-lake-id="u9647de9a" id="u9647de9a"><span data-lake-id="ucd958e56" id="ucd958e56">自动配置充分的利用了spring 4.0的条件化配置特性，那么，Spring Boot是如何实现自动配置的？Spring 4中的条件化配置又是怎么运用到Spring Boot中的呢？这要从Spring Boot的启动类说起。Spring Boot应用通常有一个名为</span><code data-lake-id="ueb489942" id="ueb489942"><span data-lake-id="u6eb615ac" id="u6eb615ac">*Application</span></code><span data-lake-id="uf1869591" id="uf1869591">的入口类，入口类中有一个</span><code data-lake-id="u33af8f06" id="u33af8f06"><span data-lake-id="u33d1f8af" id="u33d1f8af">main</span></code><span data-lake-id="u7369b17d" id="u7369b17d">方法，这个方法其实就是一个标准的Java应用的入口方法。一般在</span><code data-lake-id="u228c0e8c" id="u228c0e8c"><span data-lake-id="ud9bffd2f" id="ud9bffd2f">main</span></code><span data-lake-id="u46836beb" id="u46836beb">方法中使用</span><code data-lake-id="ub71ac411" id="ub71ac411"><span data-lake-id="u5224525c" id="u5224525c">SpringApplication.run()</span></code><span data-lake-id="u2db2e504" id="u2db2e504">来启动整个应用。值得注意的是，这个入口类要使用</span><code data-lake-id="u6f1e8c01" id="u6f1e8c01"><span data-lake-id="uc9802e7a" id="uc9802e7a">@SpringBootApplication</span></code><span data-lake-id="u1fc21bb3" id="u1fc21bb3">注解声明。</span><code data-lake-id="u06b470e2" id="u06b470e2"><span data-lake-id="u5964b3b7" id="u5964b3b7">@SpringBootApplication</span></code><span data-lake-id="u8b0074c3" id="u8b0074c3">是Spring Boot的核心注解，他是一个组合注解。</span></p>
  <p data-lake-id="u530534d5" id="u530534d5"><br></p>
  <pre lang="java"><code>
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    // 略
}
</code></pre>
  <p data-lake-id="u00d57269" id="u00d57269"><br></p>
  <p data-lake-id="u30c4a864" id="u30c4a864"><code data-lake-id="u28903a28" id="u28903a28"><span data-lake-id="u823857ab" id="u823857ab">@SpringBootApplication</span></code><span data-lake-id="ub5f46f80" id="ub5f46f80">是一个组合注解，它主要包含</span><code data-lake-id="uba3ab880" id="uba3ab880"><span data-lake-id="u1f0c4812" id="u1f0c4812">@SpringBootConfiguration</span></code><span data-lake-id="u06e125d5" id="u06e125d5">、</span><code data-lake-id="uf1c9bc06" id="uf1c9bc06"><span data-lake-id="u6d0e205c" id="u6d0e205c">@EnableAutoConfiguration</span></code><span data-lake-id="ua60096e8" id="ua60096e8">等几个注解。也就是说可以直接在启动类中使用这些注解来代替</span><code data-lake-id="ud2405f8a" id="ud2405f8a"><span data-lake-id="u8eec11c4" id="u8eec11c4">@ SpringBootApplication</span></code><span data-lake-id="u1f077606" id="u1f077606">注解。 关于Spring Boot中的Spring自动化配置主要是</span><code data-lake-id="ua13f730e" id="ua13f730e"><span data-lake-id="ub3007a95" id="ub3007a95">@EnableAutoConfiguration</span></code><span data-lake-id="u009c2677" id="u009c2677">的功劳。该注解可以让Spring Boot根据类路径中的jar包依赖为当前项目进行自动配置。</span></p>
  <p data-lake-id="u17ce96dc" id="u17ce96dc"><br></p>
  <p data-lake-id="u4493c2fb" id="u4493c2fb"><span data-lake-id="u1eb058a5" id="u1eb058a5">至此，我们知道，Spring Boot的自动化配置主要是通过</span><code data-lake-id="u72f91331" id="u72f91331"><span data-lake-id="ueddfc281" id="ueddfc281">@EnableAutoConfiguration</span></code><span data-lake-id="u32717908" id="u32717908">来实现的，因为我们在程序的启动入口使用了</span><code data-lake-id="uaff1dd23" id="uaff1dd23"><span data-lake-id="u19c070d0" id="u19c070d0">@SpringBootApplication</span></code><span data-lake-id="u1e796662" id="u1e796662">注解，而该注解中组合了</span><code data-lake-id="u90e57639" id="u90e57639"><span data-lake-id="uf9060e95" id="uf9060e95">@EnableAutoConfiguration</span></code><span data-lake-id="ue102df80" id="ue102df80">注解。所以，在启动类上使用</span><code data-lake-id="u220f2825" id="u220f2825"><span data-lake-id="ufb38648b" id="ufb38648b">@EnableAutoConfiguration</span></code><span data-lake-id="u82cc02c7" id="u82cc02c7">注解，就会开启自动配置。</span></p>
  <p data-lake-id="ua505bde4" id="ua505bde4"><br></p>
  <p data-lake-id="ud9d8536b" id="ud9d8536b"><span data-lake-id="u2a569584" id="u2a569584">那么，本着刨根问底的原则，当然要知道</span><code data-lake-id="ua5538120" id="ua5538120"><span data-lake-id="u9b3dfd1f" id="u9b3dfd1f">@EnableAutoConfiguration</span></code><span data-lake-id="u72264cb7" id="u72264cb7">又是如何实现自动化配置的，因为目前为止，我们还没有发现Spring 4中条件化配置的影子。</span></p>
  <p data-lake-id="u6f04bd77" id="u6f04bd77"><br></p>
  <h2 data-lake-id="PtgmQ" id="PtgmQ"><span data-lake-id="uddd25433" id="uddd25433">EnableAutoConfiguration</span></h2>
  <p data-lake-id="ua2e9c9e3" id="ua2e9c9e3"><br></p>
  <p data-lake-id="u401fba2f" id="u401fba2f"><span data-lake-id="ue8ac6978" id="ue8ac6978">其实Spring框架本身也提供了几个名字为</span><code data-lake-id="u420cbe74" id="u420cbe74"><span data-lake-id="u26863724" id="u26863724">@Enable</span></code><span data-lake-id="u38072dff" id="u38072dff">开头的Annotation定义。比如</span><code data-lake-id="u6b337768" id="u6b337768"><span data-lake-id="ucb11ab38" id="ucb11ab38">@EnableScheduling</span></code><span data-lake-id="ud76a183a" id="ud76a183a">、</span><code data-lake-id="u5e63d866" id="u5e63d866"><span data-lake-id="u3fb31563" id="u3fb31563">@EnableCaching</span></code><span data-lake-id="ub48677fd" id="ub48677fd">、</span><code data-lake-id="ue346fb4d" id="ue346fb4d"><span data-lake-id="u55ddee05" id="u55ddee05">@EnableMBeanExport</span></code><span data-lake-id="ue79cae90" id="ue79cae90">等，</span><code data-lake-id="uce759cea" id="uce759cea"><span data-lake-id="u73f8be3f" id="u73f8be3f">@EnableAutoConfiguration</span></code><span data-lake-id="ue6d66b10" id="ue6d66b10">的理念和这些注解其实是一脉相承的。</span></p>
  <p data-lake-id="u3c9015f6" id="u3c9015f6"><br></p>
  <blockquote data-lake-id="ud53506f1" id="ud53506f1">
   <p data-lake-id="u2b375238" id="u2b375238"><code data-lake-id="u71930ef8" id="u71930ef8"><span data-lake-id="udf4814fe" id="udf4814fe">@EnableScheduling</span></code><span data-lake-id="u7052e90b" id="u7052e90b">是通过</span><code data-lake-id="ue412d367" id="ue412d367"><span data-lake-id="u16887170" id="u16887170">@Import</span></code><span data-lake-id="u8e9e7d75" id="u8e9e7d75">将Spring调度框架相关的bean定义都加载到IoC容器。</span></p>
   <p data-lake-id="uc59d86d7" id="uc59d86d7"><span data-lake-id="u591d38a7" id="u591d38a7"> </span></p>
   <p data-lake-id="uad23ed38" id="uad23ed38"><code data-lake-id="ud43c249c" id="ud43c249c"><span data-lake-id="u8cc12f02" id="u8cc12f02">@EnableMBeanExport</span></code><span data-lake-id="u453b49c8" id="u453b49c8">是通过</span><code data-lake-id="ubd89ebb5" id="ubd89ebb5"><span data-lake-id="u792da0a8" id="u792da0a8">@Import</span></code><span data-lake-id="u3bacd245" id="u3bacd245">将JMX相关的bean定义加载到IoC容器。</span></p>
   <p data-lake-id="ud375e8bc" id="ud375e8bc"><span data-lake-id="u85caee7b" id="u85caee7b"> </span></p>
   <p data-lake-id="u73228958" id="u73228958"><code data-lake-id="u8338b6d0" id="u8338b6d0"><span data-lake-id="u43160efb" id="u43160efb">@EnableAutoConfiguration</span></code><span data-lake-id="u5d697a59" id="u5d697a59">也是借助</span><code data-lake-id="u7390e8e6" id="u7390e8e6"><span data-lake-id="u8570f637" id="u8570f637">@Import</span></code><span data-lake-id="ue70013aa" id="ue70013aa">的帮助，将所有符合自动配置条件的bean定义加载到IoC容器。</span></p>
  </blockquote>
  <p data-lake-id="u9d7710eb" id="u9d7710eb"><br></p>
  <p data-lake-id="u347f1f6d" id="u347f1f6d"><span data-lake-id="u828a5237" id="u828a5237">下面是</span><code data-lake-id="u3acec810" id="u3acec810"><span data-lake-id="u64e15e02" id="u64e15e02">EnableAutoConfiguration</span></code><span data-lake-id="u32943bd3" id="u32943bd3">注解的源码：</span></p>
  <p data-lake-id="uaac91d35" id="uaac91d35"><br></p>
  <pre lang="java"><code>
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    //略
}
</code></pre>
  <p data-lake-id="uda005d8f" id="uda005d8f"><br></p>
  <p data-lake-id="uaed705f0" id="uaed705f0"><span data-lake-id="u1f57c53d" id="u1f57c53d">观察</span><code data-lake-id="u50b73017" id="u50b73017"><span data-lake-id="u5b382198" id="u5b382198">@EnableAutoConfiguration</span></code><span data-lake-id="uab9b48d6" id="uab9b48d6">可以发现，这里</span><strong><span data-lake-id="ud7ee67b2" id="ud7ee67b2">Import</span></strong><span data-lake-id="udfc65366" id="udfc65366">了</span><code data-lake-id="ud122ee68" id="ud122ee68"><span data-lake-id="u770a36a7" id="u770a36a7">EnableAutoConfigurationImportSelector</span></code><span data-lake-id="uc68f8465" id="uc68f8465">，这就是Spring Boot自动化配置的“始作俑者”。</span></p>
  <p data-lake-id="u546c5f6c" id="u546c5f6c"><br></p>
  <p data-lake-id="u71b029b8" id="u71b029b8"><span data-lake-id="u85d183d5" id="u85d183d5">至此，我们知道，由于我们在Spring Boot的启动类上使用了</span><code data-lake-id="u6f9e3e29" id="u6f9e3e29"><span data-lake-id="uc6701237" id="uc6701237">@SpringBootApplication</span></code><span data-lake-id="u28b0530e" id="u28b0530e">注解，而该注解组合了</span><code data-lake-id="u561f2a39" id="u561f2a39"><span data-lake-id="ud0dd01d3" id="ud0dd01d3">@EnableAutoConfiguration</span></code><span data-lake-id="u6c038a48" id="u6c038a48">注解，</span><code data-lake-id="ue10a4623" id="ue10a4623"><span data-lake-id="u64cd7b8d" id="u64cd7b8d">@EnableAutoConfiguration</span></code><span data-lake-id="u03a9e958" id="u03a9e958">是自动化配置的“始作俑者”，而</span><code data-lake-id="ua4dcd5b4" id="ua4dcd5b4"><span data-lake-id="u6e7fce19" id="u6e7fce19">@EnableAutoConfiguration</span></code><span data-lake-id="u521ec5c7" id="u521ec5c7">中Import了</span><code data-lake-id="ubd3766bd" id="ubd3766bd"><span data-lake-id="ua2edaac9" id="ua2edaac9">EnableAutoConfigurationImportSelector</span></code><span data-lake-id="u524824eb" id="u524824eb">类，该注解的内部实现已经很接近我们要找的“真相”了。</span></p>
  <p data-lake-id="u9cfc6e8a" id="u9cfc6e8a"><br></p>
  <h2 data-lake-id="Zl7a3" id="Zl7a3"><span data-lake-id="u9999754a" id="u9999754a">EnableAutoConfigurationImportSelector</span></h2>
  <p data-lake-id="u8c5e8d43" id="u8c5e8d43"><br></p>
  <p data-lake-id="ueaa01999" id="ueaa01999"><code data-lake-id="u109f92e6" id="u109f92e6"><span data-lake-id="ub7345147" id="ub7345147">EnableAutoConfigurationImportSelector</span></code><span data-lake-id="u0a01076d" id="u0a01076d">的源码在这里就不贴了，感兴趣的可以直接去看一下，其实实现也比较简单，主要就是使用Spring 4 提供的的</span><code data-lake-id="u5b89347f" id="u5b89347f"><span data-lake-id="u6e62997f" id="u6e62997f">SpringFactoriesLoader</span></code><span data-lake-id="uda8c3367" id="uda8c3367">工具类。通过</span><code data-lake-id="uc1c12fc8" id="uc1c12fc8"><span data-lake-id="uec962d4c" id="uec962d4c">SpringFactoriesLoader.loadFactoryNames()</span></code><span data-lake-id="u4afaa5f3" id="u4afaa5f3">读取了ClassPath下面的</span><code data-lake-id="ubbfbf362" id="ubbfbf362"><span data-lake-id="ub746cb0d" id="ub746cb0d">META-INF/spring.factories</span></code><span data-lake-id="u5806bb9f" id="u5806bb9f">文件。</span></p>
  <p data-lake-id="u4037bc29" id="u4037bc29"><br></p>
  <blockquote data-lake-id="u0fda188a" id="u0fda188a">
   <p data-lake-id="ue3745aaf" id="ue3745aaf"><span data-lake-id="ub709e115" id="ub709e115">这里要简单提一下</span><code data-lake-id="u0982d1dc" id="u0982d1dc"><span data-lake-id="u66285625" id="u66285625">spring.factories</span></code><span data-lake-id="u26e6291c" id="u26e6291c">文件，它是一个典型的java properties文件，配置的格式为</span><code data-lake-id="u8f63a751" id="u8f63a751"><strong><span data-lake-id="u4fb3a6a3" id="u4fb3a6a3">Key = Value</span></strong></code><span data-lake-id="u0984ada2" id="u0984ada2">形式。</span></p>
  </blockquote>
  <p data-lake-id="ua54b2313" id="ua54b2313"><br></p>
  <p data-lake-id="ue47b69e5" id="ue47b69e5"><code data-lake-id="u74151913" id="u74151913"><span data-lake-id="uaf3c0764" id="uaf3c0764">EnableAutoConfigurationImportSelector</span></code><span data-lake-id="u0e661264" id="u0e661264">通过读取</span><code data-lake-id="u7701b088" id="u7701b088"><span data-lake-id="uba768c09" id="uba768c09">spring.factories</span></code><span data-lake-id="ue243fef4" id="ue243fef4">中的key为</span><code data-lake-id="ucbb1392b" id="ucbb1392b"><span data-lake-id="uf6471578" id="uf6471578">org.springframework.boot.autoconfigure.EnableAutoConfiguration</span></code><span data-lake-id="u4472fea1" id="u4472fea1">的值。如</span><code data-lake-id="ue2f7c314" id="ue2f7c314"><span data-lake-id="ua31d6678" id="ua31d6678">spring-boot-autoconfigure-1.5.1.RELEASE.jar</span></code><span data-lake-id="uc9e0f834" id="uc9e0f834">中的</span><code data-lake-id="u66950356" id="u66950356"><span data-lake-id="u765b1ec8" id="u765b1ec8">spring.factories</span></code><span data-lake-id="uced36f94" id="uced36f94">文件包含以下内容：</span></p>
  <p data-lake-id="u16708c8a" id="u16708c8a"><br></p>
  <pre lang="java"><code>
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
......
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
</code></pre>
  <p data-lake-id="u1b49a5b0" id="u1b49a5b0"><br></p>
  <p data-lake-id="ud7d75b19" id="ud7d75b19"><span data-lake-id="u9de7d366" id="u9de7d366">上面的</span><code data-lake-id="u1a766bac" id="u1a766bac"><span data-lake-id="ub90e47c1" id="ub90e47c1">EnableAutoConfiguration</span></code><span data-lake-id="uc89d8cfb" id="uc89d8cfb">配置了多个类，这些都是Spring Boot中的自动配置相关类；在启动过程中会解析对应类配置信息。每个Configuration都定义了相关bean的实例化配置。都说明了哪些bean可以被自动配置，什么条件下可以自动配置，并把这些bean实例化出来。</span></p>
  <p data-lake-id="u4b7c68bb" id="u4b7c68bb"><br></p>
  <blockquote data-lake-id="ucb7b125f" id="ucb7b125f">
   <p data-lake-id="u1eabf31a" id="u1eabf31a"><span data-lake-id="u16eba9ff" id="u16eba9ff">如果我们新定义了一个starter的话，也要在该starter的jar包中提供 </span><code data-lake-id="uf44aadba" id="uf44aadba"><span data-lake-id="u5e8e232d" id="u5e8e232d">spring.factories</span></code><span data-lake-id="uaa9d2dfd" id="uaa9d2dfd">文件，并且为其配置</span><code data-lake-id="ua22fff3b" id="ua22fff3b"><span data-lake-id="ub0ab609d" id="ub0ab609d">org.springframework.boot.autoconfigure.EnableAutoConfiguration</span></code><span data-lake-id="u2b91db14" id="u2b91db14">对应的配置类。</span></p>
  </blockquote>
  <p data-lake-id="ubaaaa7a5" id="ubaaaa7a5"><br></p>
  <h2 data-lake-id="hJaaB" id="hJaaB"><span data-lake-id="u5dcb3641" id="u5dcb3641">Configuration</span></h2>
  <p data-lake-id="u9ac6c07e" id="u9ac6c07e"><br></p>
  <p data-lake-id="u908ad905" id="u908ad905"><span data-lake-id="u14ca90e7" id="u14ca90e7">我们从</span><code data-lake-id="ub7d76328" id="ub7d76328"><span data-lake-id="ued029236" id="ued029236">spring-boot-autoconfigure-1.5.1.RELEASE.jar</span></code><span data-lake-id="udf022843" id="udf022843">中的</span><code data-lake-id="u7c12f1ec" id="u7c12f1ec"><span data-lake-id="u1642270a" id="u1642270a">spring.factories</span></code><span data-lake-id="u053791e7" id="u053791e7">文件随便找一个Configuration，看看他是如何自动加载bean的。</span></p>
  <p data-lake-id="ubd3cae05" id="ubd3cae05"><br></p>
  <pre lang="java"><code>
@Configuration
@AutoConfigureAfter({JmxAutoConfiguration.class})
@ConditionalOnProperty(
    prefix = "spring.application.admin",
    value = {"enabled"},
    havingValue = "true",
    matchIfMissing = false
)
public class SpringApplicationAdminJmxAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public SpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar() throws MalformedObjectNameException {
        String jmxName = this.environment.getProperty("spring.application.admin.jmx-name", "org.springframework.boot:type=Admin,name=SpringApplication");
        if(this.mbeanExporter != null) {
            this.mbeanExporter.addExcludedBean(jmxName);
        }

        return new SpringApplicationAdminMXBeanRegistrar(jmxName);
    }
}
</code></pre>
  <p data-lake-id="ub3c559bf" id="ub3c559bf"><br></p>
  <p data-lake-id="u10f4eac8" id="u10f4eac8"><span data-lake-id="u8cdc1559" id="u8cdc1559">看到上面的代码，终于找到了我们要找的东西——Spring 4的条件化配置。上面</span><code data-lake-id="uea22ea85" id="uea22ea85"><span data-lake-id="ub0805d3b" id="ub0805d3b">SpringApplicationAdminJmxAutoConfiguration</span></code><span data-lake-id="uc1438805" id="uc1438805">在决定对哪些bean进行自动化配置的时候，使用了两个条件注解：</span><code data-lake-id="ubd9e1409" id="ubd9e1409"><span data-lake-id="u28865307" id="u28865307">ConditionalOnProperty</span></code><span data-lake-id="uafd0707a" id="uafd0707a">和</span><code data-lake-id="u6b100a54" id="u6b100a54"><span data-lake-id="u62cfdb43" id="u62cfdb43">ConditionalOnMissingBean</span></code><span data-lake-id="uae75574e" id="uae75574e">。只有满足这种条件的时候，对应的bean才会被创建。这样做的好处是什么？这样可以保证某些bean在没满足特定条件的情况下就可以不必初始化，避免在bean初始化过程中由于条件不足，导致应用启动失败。</span></p>
  <p data-lake-id="u299fc142" id="u299fc142"><br></p>
  <p data-lake-id="u093ba689" id="u093ba689"><br></p>
 </body>
</html>